using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using DealerPlatform.Core.Core;
using DealerPlatform.Domain;
using DealerPlatform.Domain.GlobalDto;
using Microsoft.EntityFrameworkCore;

namespace DealerPlatform.Core.Repository
{
    public class Repository<TEntity> : IRepository<TEntity>
         where TEntity : class //where TEntity: BaseEntity
    {
        private readonly DealerPlatformContext _context;

        public Repository(DealerPlatformContext context)
        {
            _context = context;
        }

        public List<TEntity> GetList()
        {
            return _context.Set<TEntity>().ToList();
        }

        public async Task<List<TEntity>> GetListAsync()
        {
            return await _context.Set<TEntity>().ToListAsync();
        }

        // public List<TEntity> GetList(Func<TEntity, bool> func)
        // {
        //     return _context.Set<TEntity>().Where(p => func(p)).ToList();
        // }

        // public async Task<List<TEntity>> GetListAsync(Func<TEntity, bool> func)
        // {
        //     // return await _context.Set<TEntity>().Where(p=>func(p)).ToListAsync();    //错误的
        //     return await _context.Set<TEntity>().WhereAsync(func).ToListAsync();    //修正版
        // }

        public async Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> func)
        {
            return await _context.Set<TEntity>().Where(func).ToListAsync();    //正式版
        }

        public async Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> func, PageWithSortDto dto)
        {
            int skip = (dto.PageIndex - 1) * dto.PageSize;
            if (dto.OrderType == OrderType.Asc)
                return await _context.Set<TEntity>().Where(func).OrderByField(dto.Sort).Skip(skip).Take(dto.PageSize).ToListAsync();    //正式版
            else
                return await _context.Set<TEntity>().Where(func).OrderByField(dto.Sort, false).Skip(skip).Take(dto.PageSize).ToListAsync();    //正式版
        }

        public IQueryable<TEntity> GetQueryable()
        {
            return _context.Set<TEntity>();
        }


        // public TEntity Get(Func<TEntity, bool> func)
        // {
        //     return _context.Set<TEntity>().FirstOrDefault(func);
        // }

        public async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> func)
        {
            return await _context.Set<TEntity>().FirstOrDefaultAsync(func);
        }


        public TEntity Insert(TEntity entity)
        {
            var res = _context.Set<TEntity>().Add(entity).Entity;
            _context.SaveChanges();
            return res;
        }

        public async Task<TEntity> InsertAsync(TEntity entity)
        {
            var res = (await _context.Set<TEntity>().AddAsync(entity)).Entity;
            _context.SaveChanges();
            return res;
        }


        public TEntity Delete(TEntity entity)
        {
            var res = _context.Set<TEntity>().Remove(entity).Entity;
            _context.SaveChanges();
            return res;
        }

        public async Task<TEntity> DeleteAsync(TEntity entity)
        {
            var res = _context.Set<TEntity>().Remove(entity).Entity;
            await _context.SaveChangesAsync();
            return res;
        }


        public TEntity Update(TEntity entity)
        {
            var res = _context.Set<TEntity>().Update(entity).Entity;
            _context.SaveChanges();
            return res;
        }

        public async Task<TEntity> UpdateAsync(TEntity entity)
        {
            var res = _context.Set<TEntity>().Update(entity).Entity;
            await _context.SaveChangesAsync();
            return res;
        }
    }

    public interface IRepository
    {

    }

    public interface IRepository<TEntity> : IRepository
         where TEntity : class //where TEntity: BaseEntity
    {
        public List<TEntity> GetList();
        public Task<List<TEntity>> GetListAsync();
        // public List<TEntity> GetList(Func<TEntity, bool> func);
        // public Task<List<TEntity>> GetListAsync(Func<TEntity, bool> func);
        public Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> func);
        public Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> func, PageWithSortDto dto);
        public IQueryable<TEntity> GetQueryable();

        // public TEntity Get(Func<TEntity, bool> func);
        public Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> func);

        public TEntity Insert(TEntity entity);
        public Task<TEntity> InsertAsync(TEntity entity);

        public TEntity Delete(TEntity entity);
        public Task<TEntity> DeleteAsync(TEntity entity);

        public TEntity Update(TEntity entity);
        public Task<TEntity> UpdateAsync(TEntity entity);
    }

    public static class QueryableExtensions
    {
        public static IQueryable<T> OrderByField<T>(this IQueryable<T> q, string sortField, bool ascending = true)
        {
            var param = Expression.Parameter(typeof(T), "x");
            var prop = Expression.Property(param, sortField);
            var exp = Expression.Lambda(prop, param);
            var method = ascending ? "OrderBy" : "OrderByDescending";
            var types = new[] { q.ElementType, exp.Body.Type };
            var mce = Expression.Call(typeof(Queryable), method, types, q.Expression, exp);
            return q.Provider.CreateQuery<T>(mce);
        }
    }
}